///**
// * Copyright(c) Live2D Inc. All rights reserved.
// *
// * Use of this source code is governed by the Live2D Open Software license
// * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
// */

//#include "CubismJson.hpp"

//#include "CubismDebug.hpp"
//#include "Type/QString.hpp"

//#include <stdlib.h>

// using namespace std; // for strtof

////------------ LIVE2D NAMESPACE ------------
// namespace Live2D
//{
//    namespace Cubism
//    {
//        namespace Framework
//        {
//            namespace Utils
//            {

//                // StaticInitializeNotForClientCall()で初期化する
//                Boolean *Boolean::TrueValue = NULL;
//                Boolean *Boolean::FalseValue = NULL;
//                Value *Value::ErrorValue = NULL;
//                Value *Value::NullValue = NULL;
//                QVector<QString> *Value::s_dummyKeys = NULL;

//                void Value::StaticReleaseNotForClientCall()
//                {
//                    CSM_DELETE(Boolean::TrueValue);
//                    CSM_DELETE(Boolean::FalseValue);
//                    CSM_DELETE(Error::ErrorValue);
//                    CSM_DELETE(Value::NullValue);
//                    CSM_DELETE(Value::s_dummyKeys);

//                    Boolean::TrueValue = NULL;
//                    Boolean::FalseValue = NULL;
//                    Error::ErrorValue = NULL;
//                    Value::NullValue = NULL;
//                    Value::s_dummyKeys = NULL;
//                }

//                void Value::StaticInitializeNotForClientCall()
//                {
//                    Boolean::TrueValue = CSM_NEW Boolean(true);
//                    Boolean::FalseValue = CSM_NEW Boolean(false);

//                    Error::ErrorValue = CSM_NEW Error("ERROR", true);
//                    NullValue = CSM_NEW Utils::NullValue();

//                    Value::s_dummyKeys = CSM_NEW QVector<QString>();
//                }

//                CubismJson::CubismJson() : _error(NULL), _lineCount(0), _root(NULL)
//                {
//                }

//                CubismJson::CubismJson(const csmByte *buffer, csmInt32 length) : _error(NULL), _lineCount(0), _root(NULL)
//                {
//                    ParseBytes(buffer, length);
//                }

//                CubismJson::~CubismJson()
//                {
//                    if (_root && !_root->IsStatic())
//                    {
//                        CSM_DELETE(_root);
//                    }

//                    _root = NULL;
//                }

//                void CubismJson::Delete(CubismJson *instance)
//                {
//                    CSM_DELETE_SELF(CubismJson, instance);
//                }

//                CubismJson *CubismJson::Create(const csmByte *buffer, csmSizeInt size)
//                {
//                    CubismJson *json = CSM_NEW CubismJson();
//                    const csmBool succeeded = json->ParseBytes(buffer, size);

//                    if (!succeeded)
//                    {
//                        CubismJson::Delete(json);
//                        return NULL;
//                    }
//                    else
//                    {
//                        return json;
//                    }
//                }

//                Value &CubismJson::GetRoot() const
//                {
//                    return *_root;
//                }

//                csmBool CubismJson::ParseBytes(const csmByte *buffer, csmInt32 size)
//                {
//                    csmInt32 endPos;
//                    _root = ParseValue(reinterpret_cast<const QString &>(buffer), size, 0, &endPos);

//                    if (_error)
//                    {
//#if defined(CSM_TARGET_WIN_GL) || defined(_MSC_VER)
//                        csmChar strbuf[256] = { '\0' };
//                        _snprintf_s(strbuf, 256, 256, "Json parse error : @line %d\n", (_lineCount + 1));
//                        _root = CSM_NEW String(strbuf);
//#else
//                        csmChar strbuf[256] = { '\0' };
//                        snprintf(strbuf, 256, "Json parse error : @line %d\n", (_lineCount + 1));
//                        _root = CSM_NEW String(strbuf);
//#endif
//                        CubismLogInfo("%s", _root->GetString());
//                        return false;
//                    }
//                    else if (_root == NULL)
//                    {
//                        _root = CSM_NEW Error(_error, false); // rootは開放されるのでエラーオブジェクトを別途作る
//                        return false;
//                    }
//                    return true;
//                }

//                QString CubismJson::ParseString(const QString &string, csmInt32 length, csmInt32 begin, csmInt32 *outEndPos)
//                {
//                    if (_error)
//                        return NULL;
//                    csmInt32 i = begin;
//                    csmChar c, c2;
//                    QString ret;
//                    csmInt32 buf_start = begin; // sbufに登録されていない文字の開始位置

//                    for (; i < length; i++)
//                    {
//                        c = static_cast<csmChar>(string[i] & 0xFF);

//                        switch (c)
//                        {
//                            case '\"':
//                            {                       //終端の”, エスケープ文字は別に処理されるのでここにはこない
//                                *outEndPos = i + 1; // ”の次の文字
//                                ret.Append(static_cast<const QString &>(string + buf_start), (i - buf_start));
//                                return ret;
//                            }
//                            case '\\':
//                            {        //エスケープの場合
//                                i++; //２文字をセットで扱う

//                                if (i - 1 > buf_start)
//                                    ret.Append(static_cast<const QString &>(string + buf_start), (i - buf_start - 1));
//                                    //前の文字までを登録する
//                                buf_start = i + 1; //エスケープ（２文字）の次の文字から

//                                if (i < length)
//                                {
//                                    c2 = static_cast<csmChar>(string[i] & 0xFF);
//                                    switch (c2)
//                                    {
//                                        case '\\': ret.Append(1, '\\'); break;
//                                        case '\"': ret.Append(1, '\"'); break;
//                                        case '/': ret.Append(1, '/'); break;

//                                        case 'b': ret.Append(1, '\b'); break;
//                                        case 'f': ret.Append(1, '\f'); break;
//                                        case 'n': ret.Append(1, '\n'); break;
//                                        case 'r': ret.Append(1, '\r'); break;
//                                        case 't': ret.Append(1, '\t'); break;
//                                        case 'u': _error = "parse string/unicode escape not supported";
//                                        default: break;
//                                    }
//                                }
//                                else
//                                {
//                                    _error = "parse string/escape error";
//                                }
//                                break;
//                            }
//                            default:
//                            {
//                                break;
//                            }
//                        }
//                    }
//                    _error = "parse string/illegal end";
//                    return NULL;
//                }

//                Value *CubismJson::ParseObject(const QString &buffer, csmInt32 length, csmInt32 begin, csmInt32 *outEndPos)
//                {
//                    if (_error)
//                        return NULL;
//                    Map *ret = CSM_NEW Map();

//                    // key : value ,
//                    QString key;
//                    csmInt32 i = begin;
//                    csmChar c;
//                    csmInt32 local_ret_endpos2[1];
//                    csmBool ok = false;

//                    // , が続く限りループ
//                    for (; i < length; i++)
//                    {
//                        for (; i < length; i++)
//                        {
//                            c = static_cast<csmChar>(buffer[i] & 0xFF);

//                            switch (c)
//                            {
//                                case '\"':
//                                    key = ParseString(buffer, length, i + 1, local_ret_endpos2);
//                                    if (_error)
//                                        return NULL;
//                                    i = local_ret_endpos2[0];
//                                    ok = true;
//                                    goto BREAK_LOOP1; //-- loopから出る
//                                case '}':             //閉じカッコ
//                                    *outEndPos = i + 1;
//                                    return ret; //空
//                                case ':': _error = "illegal ':' position"; break;
//                                case '\n': _lineCount++;
//                                default: break; //スキップする文字
//                            }
//                        }
//                    BREAK_LOOP1:
//                        if (!ok)
//                        {
//                            _error = "key not found";
//                            return NULL;
//                        }

//                        ok = false;

//                        // : をチェック
//                        for (; i < length; i++)
//                        {
//                            c = static_cast<csmChar>(buffer[i] & 0xFF);

//                            switch (c)
//                            {
//                                case ':':
//                                    ok = true;
//                                    i++;
//                                    goto BREAK_LOOP2; //-- loopから出る

//                                case '}': _error = "illegal '}' position"; break;
//                                case '\n':
//                                    _lineCount++;
//                                    // case ' ': case '\t': case '\r':
//                                default: break; //スキップする文字
//                            }
//                        }
//                    BREAK_LOOP2:

//                        if (!ok)
//                        {
//                            _error = "':' not found";
//                            return NULL;
//                        }

//                        // 値をチェック
//                        Value *value = ParseValue(buffer, length, i, local_ret_endpos2);
//                        if (_error)
//                            return NULL;
//                        i = local_ret_endpos2[0];
//                        // ret.put( key , value ) ;
//                        ret->Put(key, value);

//                        for (; i < length; i++)
//                        {
//                            c = static_cast<csmChar>(buffer[i] & 0xFF);

//                            switch (c)
//                            {
//                                case ',': goto BREAK_LOOP3;
//                                case '}': *outEndPos = i + 1; return ret; // << [] 正常終了 >>
//                                case '\n':
//                                    _lineCount++;
//                                    // case ' ': case '\t': case '\r':
//                                default: break; //スキップ
//                            }
//                        }
//                    BREAK_LOOP3:; // dummy
//                    }

//                    _error = "illegal end of parseObject";
//                    return NULL;
//                }

//                Value *CubismJson::ParseArray(const QString &buffer, csmInt32 length, csmInt32 begin, csmInt32 *outEndPos)
//                {
//                    if (_error)
//                        return NULL;
//                    Array *ret = CSM_NEW Array();

//                    // key : value ,
//                    csmInt32 i = begin;
//                    csmChar c;
//                    csmInt32 local_ret_endpos2[1];

//                    // , が続く限りループ
//                    for (; i < length; i++)
//                    {
//                        // : をチェック
//                        Value *value = ParseValue(buffer, length, i, local_ret_endpos2);
//                        if (_error)
//                            return NULL;
//                        i = local_ret_endpos2[0];
//                        if (value)
//                        {
//                            ret->Add(value);
//                        }

//                        // FOR_LOOP3:
//                        // bool breakflag = false;
//                        for (; i < length; i++)
//                        {
//                            c = static_cast<csmChar>(buffer[i] & 0xFF);

//                            switch (c)
//                            {
//                                case ',':
//                                    // breakflag = true;
//                                    // break;//次のKEY,VALUEへ
//                                    goto BREAK_LOOP3;
//                                case ']': *outEndPos = i + 1; return ret; //終了
//                                case '\n':
//                                    ++_lineCount;
//                                    // case ' ': case '\t': case '\r':
//                                default: break; //スキップ
//                            }
//                        }
//                    BREAK_LOOP3:; // dummy
//                    }

//                    CSM_DELETE(ret);
//                    _error = "illegal end of parseObject";
//                    return NULL;
//                }

//                Value *CubismJson::ParseValue(const QString &buffer, csmInt32 length, csmInt32 begin, csmInt32 *outEndPos)
//                {
//                    if (_error)
//                        return NULL;

//                    Value *o = NULL;
//                    csmInt32 i = begin;
//                    csmFloat32 f;
//                    QString s1; //デバッグ用に使っている

//                    for (; i < length; i++)
//                    {
//                        csmChar c = static_cast<csmChar>(buffer[i] & 0xFF);

//                        switch (c)
//                        {
//                            case '-':
//                            case '.':
//                            case '0':
//                            case '1':
//                            case '2':
//                            case '3':
//                            case '4':
//                            case '5':
//                            case '6':
//                            case '7':
//                            case '8':
//                            case '9':
//                            {
//                                char *ret_ptr;
//                                f = strtof(const_cast<QString &>(buffer + i), &ret_ptr);
//                                *outEndPos = static_cast<csmInt32>(ret_ptr - buffer);
//                                return CSM_NEW Float(f);
//                            }
//                            case '\"': return CSM_NEW String(ParseString(buffer, length, i + 1, outEndPos)); //\"の次の文字から
//                            case '[': o = ParseArray(buffer, length, i + 1, outEndPos); return o;
//                            case '{': o = ParseObject(buffer, length, i + 1, outEndPos); return o;
//                            case 'n': // null以外にない
//                                if (i + 3 < length)
//                                {
//                                    o = CSM_NEW NullValue(); //開放できるようにする
//                                    *outEndPos = i + 4;
//                                }
//                                else
//                                    _error = "parse null";
//                                return o;
//                            case 't': // true以外にない
//                                if (i + 3 < length)
//                                {
//                                    o = Boolean::TrueValue;
//                                    *outEndPos = i + 4;
//                                }
//                                else
//                                    _error = "parse true";
//                                return o;
//                            case 'f': // false以外にない
//                                if (i + 4 < length)
//                                {
//                                    o = Boolean::FalseValue;
//                                    *outEndPos = i + 5;
//                                }
//                                else
//                                    _error = "parse false";
//                                return o;
//                            case ',': // Array separator
//                                _error = "illegal ',' position";
//                                return NULL;
//                            case ']':           //不正な}だがスキップする。配列の最後に不要な , があると思われる
//                                *outEndPos = i; //同じ文字を再処理
//                                return NULL;
//                            case '\n': _lineCount++;
//                            case ' ':
//                            case '\t':
//                            case '\r':
//                            default: //スキップ
//                                break;
//                        }
//                    }

//                    _error = "illegal end of value";
//                    return NULL;
//                }

//                Map::~Map()
//                {
//                    csmMap<QString, Value *>::const_iterator ite = _map.Begin();
//                    while (ite != _map.End())
//                    {
//                        Value *v = (*ite).Second;
//                        if (v && !v->IsStatic())
//                            CSM_DELETE(v);
//                        ++ite;
//                    }

//                    if (_keys)
//                        CSM_DELETE(_keys);
//                }

//                Array::~Array()
//                {
//                    QVector<Value *>::iterator ite = _array.Begin();
//                    for (; ite != _array.End(); ++ite)
//                    {
//                        Value *v = (*ite);
//                        if (v && !v->IsStatic())
//                            CSM_DELETE(v);
//                    }
//                }
//            } // namespace Utils
//        }     // namespace Framework
//    }         // namespace Cubism
//} // namespace Live2D
////------------ LIVE2D NAMESPACE ------------
